/*
 * All rights Reserved, Designed By cloudland Copyright(C) 2010-2014
 *
 * fileName:  ConstantsException.java
 * author:  jinqiang
 * Company:  Cloudland Studio
 * Createdate:  2013-9-15 下午1:51:54
 *   
 * Modification  History:
 *     Date           Author        Version        
 * -------------------------------------------
 * 2013-9-15          jinqiang            1.0        
 *
 * Why & What is modified:
 * 1.0: 文件创建
 */
package org.cloudland.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.junit.Assert;

 /**
 * <pre> 
 * 使用dom4j进行xml读取的工具类
 * </pre>
 * @ClassName  XMLResolve
 * @author  jinqiang
 * @version  %I%, %G%
 * @see  
 * @since   JDK1.6
 *
 */
public final class XMLResolve
{
    private Document document=null;
    /**
     * 默认的空参构造方法
     * default constructor
     * @throws DocumentException 
     */
    private XMLResolve(Reader in) throws DocumentException{
        SAXReader reader=new SAXReader();
        document = reader.read(in);
    }
    
    /**
     * 
     * doInstance
     * 按给定的xml访问路径取得xml操作的实例对象
     * @param xmlPath
     * @return
     * @throws FileNotFoundException 
     */
    public static XMLResolve doInstance(String xmlPath) 
    {
        XMLResolve resolve = null;
        try
        {
            File f = new File(xmlPath);
            resolve = new XMLResolve(new InputStreamReader(new FileInputStream(f)));
        }
        catch(FileNotFoundException f)
        {
            //Dailys.error("XMLResolve获取实例方法无法找到指定的路径的文件", f);
        }
        catch (DocumentException e)
        {
            //Dailys.error("XMLResolve构建实例失败", e);
        }
        
        
        return resolve;
    }
    
    /**
     * 
     * doInstance
     * 重载获取操作实例的方法，参数为输入流
     * @param xmlPath
     * @return
     */
    public static XMLResolve doInstance(InputStream stream){
        XMLResolve resolve = null;
        try
        {
            resolve = new XMLResolve(new InputStreamReader(stream));
        }
        catch (DocumentException e)
        {
            //Dailys.error("XMLResolve构建实例失败", e);
        }
        
        return resolve;
    }
    
    /**
     * 
     * doInstance
     * 重载获取操作实例的方法，参数为Reader流
     * @param xmlPath
     * @return
     */
    public static XMLResolve doInstance(Reader reader){
        XMLResolve resolve = null;
        try
        {
            resolve = new XMLResolve(reader);
        }
        catch (DocumentException e)
        {
            //Dailys.error("XMLResolve构建实例失败", e);
        }
        
        return resolve;
    }
    
    /**
     * 取得xml文件的根节点元素
     * getXMLRootElement
     *
     * @return
     */
    public final XMLEntry getXMLRootElement()
    {
        Element element=document.getRootElement();
        XMLEntry xmlEntry=new XMLEntry();
        xmlEntry.setRoot(element.getName());
        xmlEntry.setValue(element.getText());
        xmlEntry.setElement(element);
        List<?> attributes=element.attributes();
        for(int j=0;j<attributes.size();j++)
        {
            Attribute attribute=(Attribute)attributes.get(j);
            xmlEntry.putAttributeMap(attribute.getName(),attribute.getText());
        }
        return xmlEntry;
    }
    
    /**
     * 
     * getCurrentElement
     *  按节点表达式只获取xml文件中节点不包括子节点的内容
     * @return
     */
    public final List<XMLEntry> getCurrentElement(final String element)
    {
         List<XMLEntry> xmlEntryList=new ArrayList<XMLEntry>();
        if(element!=null&&!"".equals(element))
        {
            List<?> elements=document.selectNodes(element);
            for(int i=0;i<elements.size();i++)
            {
                XMLEntry xmlEntry=new XMLEntry();
                Element temp=(Element)elements.get(i);
                xmlEntry.setRoot(temp.getName());
                xmlEntry.setValue(temp.getText());
                xmlEntry.setElement(temp);
                List<?> attributes=temp.attributes();
                for(int j=0;j<attributes.size();j++)
                {
                    Attribute attribute=(Attribute)attributes.get(j);
                    xmlEntry.putAttributeMap(attribute.getName(),attribute.getText());
                }
                xmlEntryList.add(xmlEntry);
            }
        }
        return xmlEntryList;
    }
    
    /**
     * 
     * getChildElement
     *  按节点表达式来获取xml文件中对应的所有对应节点和子节点的内容
     * @return
     */
    public final List<XMLEntry> getChildElement(final XMLEntry currentNode)
    {
         List<XMLEntry> xmlEntryList=new ArrayList<XMLEntry>();
        if(currentNode!=null&&currentNode.getElement()!=null)
        {
            List<?> elements=currentNode.getElement().elements();
            for(int i=0;i<elements.size();i++)
            {
                Element temp=(Element)elements.get(i);
                XMLEntry xmlEntry=new XMLEntry();
                xmlEntry.setRoot(temp.getName());
                xmlEntry.setValue(temp.getText());
                xmlEntry.setElement(temp);
                List<?> attributes=temp.attributes();
                for(int j=0;j<attributes.size();j++)
                {
                    Attribute attribute=(Attribute)attributes.get(j);
                    xmlEntry.putAttributeMap(attribute.getName(),attribute.getText());
                }
                xmlEntryList.add(xmlEntry);
            }
        }
        return xmlEntryList;
    }

    /**
     * 
     * getXMLElementSource
     *  获取xml文件中的节点源xml内容
     * @return
     */
    public final List<String> getXMLElementSource(final String element)
    {
         List<String> resultList=new ArrayList<String>();
        if(element!=null&&!"".equals(element))
        {
            List<?> elements=document.selectNodes(element);
            for(int i=0;i<elements.size();i++)
            {
                Element temp=(Element)elements.get(i);
                resultList.add(temp.asXML());
            }
        }
        return resultList;
    }
    
    /**
     * 
     * getCurrentElementById
     *  按节点表达式及节点的id只获取xml文件中节点不包括子节点的内容
     * @return
     */
    public final XMLEntry getCurrentElementById(final String element,final String id)
    {
         XMLEntry resultXmlEntryList=new XMLEntry();
         boolean flag=false;
        if(element!=null&&!"".equals(element))
        {
            List<?> elements=document.selectNodes(element);
            for(int i=0;i<elements.size();i++)
            {
                XMLEntry xmlEntry=new XMLEntry();
                Element temp=(Element)elements.get(i);
                xmlEntry.setRoot(temp.getName());
                xmlEntry.setValue(temp.getText());
                List<?> attributes=temp.attributes();
                for(int j=0;j<attributes.size();j++)
                {
                    Attribute attribute=(Attribute)attributes.get(j);
                    xmlEntry.putAttributeMap(attribute.getName(),attribute.getText());
                    if(attribute.getText().equals(id))
                    {
                        flag=true;
                        break;
                    }
                }
               if(flag)
               {
                   resultXmlEntryList=xmlEntry;
                   break;
               }
            }
        }
        return resultXmlEntryList;
    }
    
    public static class XMLEntry{
        private String root;//节点名
        private String value;//节点的值
        private Map<String,String> attributeMap=new HashMap<String,String>();//当前节点的attribute的map对象
        private Element element;//当前节点对象
        
        /**
         * 取得当前节点的节点名称
         * @return root
         */
         public String getName()
        {
            return root;
        }
        /**
         * set root
         * @param root the value of root
         */
        private void setRoot(String root)
        {
            this.root = root;
        }
        
        private Element getElement()
        {
            return element;
        }
        
        /**
         * 设置当前对象
         * setElement
         *
         * @param element
         */
        private void setElement(Element element)
        {
            this.element=element;
        }
        
        /**
         * 取得当前节点的文本值
         * @return value
         */
        public String getText()
        {
            return value;
        }
        /**
         * set value
         * @param value the value of value
         */
        private void setValue(String value)
        {
            this.value = value;
        }
        

        
        /**
         * 取得当前节点的属性值
         * getAttributeValue
         *
         * @param attributeName
         * @return
         */
        public String getAttribute(String attributeName)
        {
            if(attributeName==null)
            {
                return "";
            }
            else
            {
                return attributeMap.get(attributeName.toLowerCase());
            }
        }
 
        /**
         * 向当前节点的属性map对象中put对应关系
         * putAttributeMap
         *
         * @param key
         * @param value
         */
        private void putAttributeMap(String key,String value)
        {
            if(key!=null)
            {
                attributeMap.put(key.toLowerCase(), value);    
            }
        }
     
        /**
         * 获取当前节点的属性的map对象key值
         * attributeKeySet
         *
         * @return
         */
        public Set<String> attributeKeySet()
        {
            return attributeMap.keySet();
        }
        
        /***
         * 获取当前节点下的xml源文件不解析
         * getSource
         *
         * @return
         */
        public String getSource()
        {
            if(element!=null)
            {
                return element.asXML();
            }
            else
            {
                return "";
            }
        }
        
        /**
         * 
         * getChild
         *  取当前节点下对应的所有直属子节点的内容
         * @return
         */
        public final List<XMLEntry> getChild()
        {
             List<XMLEntry> xmlEntryList=new ArrayList<XMLEntry>();
            if(element!=null)
            {
                List<?> elements=element.elements();//取得该节点下的所有直属子元素
                for(int i=0;i<elements.size();i++)
                {
                    Element temp=(Element)elements.get(i);
                    XMLEntry xmlEntry=new XMLEntry();
                    xmlEntry.setRoot(temp.getName());
                    xmlEntry.setValue(temp.getText());
                    xmlEntry.setElement(temp);
                    List<?> attributes=temp.attributes();
                    for(int j=0;j<attributes.size();j++)
                    {
                        Attribute attribute=(Attribute)attributes.get(j);
                        xmlEntry.putAttributeMap(attribute.getName(),attribute.getText());
                    }//end for
                    xmlEntryList.add(xmlEntry);
                }//end for
            }//end if
            return xmlEntryList;
        }
        
        /**
         * 
         * getChild
         * 取该节点下指定名称的直属子节点的内容
         * 如：&lt;book&gt;&lt;page&gt;&lt;/page&gt;&lt;/book&gt;
         * 当前节点为book,则getChild("page");可以获取该节点下所有节点名称为page的节点元素集合
         * 如果需要传多级目录的节点&lt;book&gt;&lt;book&gt;&lt;page&gt;&lt;/page&gt;&lt;/book&gt;&lt;/book&gt;
         * 当前节点为book，需要查该节点下的page子节点，则传递表达式如：book/page
         * @return
         */
        public final List<XMLEntry> getChild(final String nodeName)
        {
            Assert.assertNotNull(nodeName,"取直属子节点需要制定节点名称，否则无法取具体节点");
            
            String nodePath = nodeName;
            if (nodePath.startsWith("/"))
            {
                nodePath = nodePath.substring(1);
            }
            if (nodePath.endsWith("/"))
            {
                nodePath = nodePath.substring(0,nodePath.length()-1);
            }
            
            String[] nodeNames = nodePath.split("/");
            
            List<XMLEntry> xmlEntryList=new ArrayList<XMLEntry>();
            if (element!=null&&nodeNames.length>0)
            {
                XMLEntry parameterEntry = new XMLEntry();
                parameterEntry.setElement(element);
                List<XMLEntry> tempList = new ArrayList<XMLEntry>();
                tempList.add(parameterEntry);
                tempList = findMatchNode(tempList, nodeNames[0]);
                parameterEntry = null;
                for (int i=1; i<nodeNames.length; i++)
                {
                    tempList = findMatchNode(tempList, nodeNames[i]);
                }
                xmlEntryList =tempList;
                tempList = null;
            }//end if
            return xmlEntryList;
        }
        
        /**
         * 
         * findMatchNode
         * 按给定的表达式递归查找给定的子元素
         * @param findElement
         * @param nodeName
         * @return
         */
        private final List<XMLEntry> findMatchNode(List<XMLEntry> findElement, String nodeName)
        {
            List<XMLEntry> xmlEntryList = new ArrayList<XMLEntry>();
            if (findElement==null || findElement.size()==0)
            {
               return xmlEntryList;
            }
            for (XMLEntry xmlElement : findElement)
            {
                    List<?> elements=xmlElement.getElement().elements();
                    for (int i=0;i<elements.size();i++)
                    {
                        Element temp=(Element)elements.get(i);
                        if (nodeName.equals(temp.getName()))//判断与指定的节点名称相同的直属子节点
                        {
                            XMLEntry xmlEntry=new XMLEntry();
                            xmlEntry.setRoot(temp.getName());
                            xmlEntry.setValue(temp.getText());
                            xmlEntry.setElement(temp);
                            List<?> attributes=temp.attributes();
                            for (int j=0;j<attributes.size();j++)
                            {
                                Attribute attribute=(Attribute)attributes.get(j);
                                xmlEntry.putAttributeMap(attribute.getName(),attribute.getText());
                            }//end for
                            xmlEntryList.add(xmlEntry);
                        }//end if
                    }//end for
            }//end for
            return xmlEntryList;
        }
    }
    
 
  
}
